package service

import (
	"context"
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"insighttracking/common/utils"
	"insighttracking/query/bo"
	"insighttracking/query/dao"
	"insighttracking/query/model"
	"time"
)

type _ordersSpuService struct{}

func (s _ordersSpuService) CreateApi(ctx context.Context, tx *dao.QueryTx, ordersID int64, customerID int64, customerName string, expireDate string) (err error) {
	ordersDetailEntities, err := tx.OrdersDetailEntity.WithContext(ctx).Where(dao.OrdersDetailEntity.OrdersID.Eq(ordersID)).Find()
	if err != nil {
		return
	}
	spuCountMap := make(map[int64]decimal.Decimal)
	for _, v := range ordersDetailEntities {
		if v.SpuID != 0 {
			if _, ok := spuCountMap[v.SpuID]; !ok {
				spuCountMap[v.SpuID] = v.SpuCount
			} else {
				spuCountMap[v.SpuID] = spuCountMap[v.SpuID].Add(v.SpuCount)
			}
		} else {
			dishID := v.DishesID
			dishRatio, err := DishService.GetSpuRatioApi(ctx, dishID)
			if err != nil {
				return err
			}
			for _, item := range dishRatio {
				if _, ok := spuCountMap[item.SpuID]; !ok {
					spuCountMap[item.SpuID] = v.SpuCount.Mul(decimal.New(item.Percent, 0)).Div(decimal.New(10000, 0))
				} else {
					spuCountMap[item.SpuID] = spuCountMap[item.SpuID].Add(v.SpuCount.Mul(decimal.New(item.Percent, 0)).Div(decimal.New(10000, 0)))
				}
			}
		}
	}

	if len(spuCountMap) == 0 {
		return errors.New("订单数据错误")
	}

	spuIDs := make([]int64, 0, len(spuCountMap))
	for spuID, _ := range spuCountMap {
		spuIDs = append(spuIDs, spuID)
	}
	spuBos, err := SpuService.GetSpuDetailByIdListApi(ctx, spuIDs)
	spuMap := make(map[int64]*bo.SpuBo)
	for _, spu := range spuBos {
		spuMap[spu.ID] = spu
	}

	data := make([]*model.OrdersSpuEntity, 0)
	for spuID, count := range spuCountMap {
		fmt.Println("utils.DateTimeStrToTime(\"0000-00-00 00:00:00.000\")", utils.DateTimeStrToTime("0000-00-00 00:00:00.000"))
		data = append(data, &model.OrdersSpuEntity{
			OrdersID:        ordersID,
			SpuID:           spuID,
			SpuName:         spuMap[spuID].Name,
			SpuType:         spuMap[spuID].SpuType,
			RequireCount:    count,
			SalsePrice:      spuMap[spuID].SalesPrice,
			ProductImageURL: spuMap[spuID].ProductImageURL,
			CatogoryID:      spuMap[spuID].CategoryId,
			CatogoryName:    spuMap[spuID].CategoryName,
			CustomerID:      customerID,
			CustomerName:    customerName,
			SupplierID:      spuMap[spuID].SupplierID,
			Supplier:        spuMap[spuID].SupplierName,
			UnitID:          spuMap[spuID].UnitID,
			UnitName:        spuMap[spuID].UnitName,
			BrandID:         spuMap[spuID].BrandID,
			BrandName:       spuMap[spuID].BrandName,
			ReceiveTime:     time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC),
			DeliveryTime:    time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC),
			ExpectedDate:    utils.DateTimeStrToTime(expireDate),
		})
	}
	err = tx.OrdersSpuEntity.CreateInBatches(data, len(data))
	return
}

func (s _ordersSpuService) GetBySpuIDApi(ctx context.Context, ordersID, spuID int64) (*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.OrdersID.Eq(ordersID), dao.OrdersSpuEntity.SpuID.Eq(spuID)).First()
}

func (s _ordersSpuService) GetListByOrdersIDApi(ctx context.Context, ordersID int64) ([]*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.OrdersID.Eq(ordersID)).Find()
}

func (s _ordersSpuService) GetUnshippedListByOrdersIDApi(ctx context.Context, ordersID int64) ([]*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(
		dao.OrdersSpuEntity.OrdersID.Eq(ordersID), dao.OrdersSpuEntity.DeliveryStatus.Eq(0)).Find()
}

func (s _ordersSpuService) GetUnReceivedListByOrdersIDApi(ctx context.Context, ordersID int64) ([]*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(
		dao.OrdersSpuEntity.OrdersID.Eq(ordersID), dao.OrdersSpuEntity.ReceiveStatus.Eq(0)).Find()
}

func (s _ordersSpuService) ModifyByIDApi(ctx context.Context, tx *dao.QueryTx, id int64, value map[string]any) error {
	_, err := tx.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.ID.Eq(id)).Updates(value)
	return err
}

func (s _ordersSpuService) ModifyByOrdersIDApi(ctx context.Context, tx *dao.QueryTx, ordersID int64, value map[string]any) error {
	_, err := tx.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.OrdersID.Eq(ordersID)).Updates(value)
	return err
}

func (s _ordersSpuService) GetListByIDApi(ctx context.Context, ids []int64) ([]*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.ID.In(ids...)).Find()
}

func (s _ordersSpuService) GetByIDApi(ctx context.Context, id int64) (*model.OrdersSpuEntity, error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.ID.Eq(id)).First()
}

func (s _ordersSpuService) GetOrgRequireByIDs(ctx context.Context, enterpriseID int64, ids []int64) (resp map[int64]*bo.SpuRequireInfo, err error) {
	resp = make(map[int64]*bo.SpuRequireInfo)
	entities, err := dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.ID.In(ids...)).Find()
	if err != nil {
		return
	}

	for _, item := range entities {

		var orgID int64
		_ = dao.SpuBomEntity.WithContext(ctx).Where(dao.SpuBomEntity.SpuID.Eq(item.SpuID)).Pluck(dao.SpuBomEntity.OrgSpuID, &orgID)
		// 没有原材料，只需要计算自身的库存
		if orgID == 0 {
			orgID = item.SpuID
			spuEntity, _ := SpuService.GetSpuDetailByIdApi(ctx, orgID)
			inventory := SpuInventoryService.GetAllSpuInventoryApi(ctx, enterpriseID, orgID)
			requireCount := item.RequireCount.Sub(inventory)
			if requireCount.Compare(decimal.Zero) < 0 {
				requireCount = decimal.Zero
			}
			if _, ok := resp[orgID]; ok {
				resp[orgID].Count = resp[orgID].Count.Add(requireCount)
			} else {
				value := bo.SpuRequireInfo{
					SpuID:                orgID,
					Count:                requireCount,
					Entity:               spuEntity,
					OrdersSpuID:          item.ID,
					ExpectationGoodsDate: item.ExpectedDate,
				}
				resp[orgID] = &value
			}
		} else {
			// 有原材料，拿到原材料库存，计算损耗率，再拿自身库存，反除损耗率
			orgSpuEntity, _ := SpuService.GetSpuDetailByIdApi(ctx, orgID)
			spuEntity, _ := SpuService.GetSpuDetailByIdApi(ctx, item.SpuID)
			orgInventory := SpuInventoryService.GetAllSpuInventoryApi(ctx, enterpriseID, orgID)
			inventory := SpuInventoryService.GetAllSpuInventoryApi(ctx, enterpriseID, item.SpuID)
			requireCount := item.RequireCount.Sub(inventory).Sub(orgInventory.Mul(spuEntity.LossRate).Div(decimal.New(100, 0))).Div(decimal.New(100, 0).Sub(spuEntity.LossRate).Div(decimal.New(100, 0)))
			if _, ok := resp[orgID]; ok {
				resp[orgID].Count = resp[orgID].Count.Add(requireCount)
			} else {
				value := bo.SpuRequireInfo{
					SpuID:                orgID,
					Count:                requireCount,
					Entity:               orgSpuEntity,
					OrdersSpuID:          item.ID,
					ExpectationGoodsDate: item.ExpectedDate,
				}
				resp[orgID] = &value
			}
		}
	}
	return
}

func (s _ordersSpuService) GetSpuListByIDApi(ctx context.Context, ids []int64) (bo []*bo.OrdersSpuGroup, err error) {
	err = dao.OrdersSpuEntity.WithContext(ctx).
		Select(
			dao.OrdersSpuEntity.ID.GroupConcat().As("ID"),
			dao.OrdersSpuEntity.SpuID.Count().As("Count"),
			dao.OrdersSpuEntity.RequireCount.Sum().As("RequireCount"),
			dao.OrdersSpuEntity.SpuID, dao.OrdersSpuEntity.SpuName,
			dao.OrdersSpuEntity.ProductImageURL,
			dao.OrdersSpuEntity.UnitName,
		).
		Where(dao.OrdersSpuEntity.OrdersID.In(ids...)).Group(dao.OrdersSpuEntity.SpuID).Scan(&bo)
	return
}

func (s _ordersSpuService) GetSpuOrdersListApi(ctx context.Context, ordersIDs []int64, spuID int64) (resp []*model.OrdersSpuEntity, err error) {
	return dao.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.OrdersID.In(ordersIDs...), dao.OrdersSpuEntity.SpuID.Eq(spuID)).Find()
}

func (s _ordersSpuService) SendApi(ctx context.Context, tx *dao.QueryTx, id int64, value map[string]any) error {
	_, err := tx.OrdersSpuEntity.WithContext(ctx).Where(dao.OrdersSpuEntity.ID.Eq(id)).Updates(value)
	return err
}

var OrdersSpuService = new(_ordersSpuService)
